Puzzle.prototype = {
  el: null,
  oPuzzle: null,
  layer: null,
  oEmptyBlock: null,
  puzzleHeight: 0,
  puzzleHeight: 0,
  row: 0,
  col: 0,
  blockWidth: 0,
  blockHeight: 0,
  blockImgPosition: [],
  blockPosition: [],
  puzzleImg: '',
  timer: null,
  startTime: 0,
  tipCallback: null,
  resCallback: null,
  // 初始化入口
  init: function (options) {
    this.initData(options);
    this.render();
    this.handle();
  },
  // 初始化数据
  initData: function (options) {
    this.el = document.querySelector(options.el);
    // 设置游戏大小
    this.puzzleWidth = options.data.width;
    this.puzzleHeight = options.data.height;
    // 设置横列数难
    this.row = options.data.row;
    this.col = options.data.col;
    // 每滑块的大小
    this.blockWidth = this.puzzleWidth / this.col;
    this.blockHeight = this.puzzleHeight / this.row;
    // 每块方块坐标
    this.blockImgPosition = this.getBlockImgPosition();
    // 打乱图片坐标
    this.blockPosition = this.getBlockPosition();
    // 传入的图片
    this.puzzleImg = options.data.img;
    // 设置回调
    this.tipCallback = options.data.tipCallback;
    this.resCallback = options.data.resCallback;
    // 异步渲染完成后获取值
    setTimeout(() => {
      this.oEmptyBlock = this.oPuzzle.querySelector('div[ref=empty]');
      this.oBlockList = this.oPuzzle.querySelectorAll('div[ref=block]');
    }, 0);
  },
  getBlockImgPosition: function () {
    var arr = [];
    for (var i = 0; i < this.row; i++) {
      for (var j = 0; j < this.col; j++) {
        arr.push({
          x: j * this.blockWidth,
          y: i * this.blockHeight,
        })
      }
    }
    return arr;
  },
  getBlockPosition: function () {
    // 声明一个新数组
    var newArr = [];
    // 每块坐标
    for (var i = 0; i < this.blockImgPosition.length; i++) {
      newArr[i] = this.blockImgPosition[i];
    }
    var lastEle = newArr[newArr.length - 1]; // 获得新数组中最后一项（为空白块）
    newArr.length = newArr.length - 1; // 将新数组的长度减一，即删掉最后一项
    newArr.sort(function () { // 打乱新数组
      return Math.random() - 0.5;
    });
    newArr.push(lastEle); // 打乱完毕后，向新数组中添加之前删除的最后一项
    return newArr;
  },
  render: function () {
    var puzzle = document.querySelector(".puzzle");
    // 只创建一次游戏容器
    if (!puzzle) {
      this.oPuzzle = document.createElement('div');
      this.el.appendChild(this.oPuzzle);
    } else {
      this.oPuzzle = puzzle;
    }
    var layer = document.querySelector(".layer");
    if (!layer) {
      this.layer = document.createElement('div');
      this.el.appendChild(this.layer);
    } else {
      this.layer = layer;
    }
    // 方块区
    var template = '';
    for (var i = 0; i < this.blockImgPosition.length; i++) {
      // 方块坐标
      var blockImgX = this.blockImgPosition[i].x;
      var blockImgY = this.blockImgPosition[i].y;
      // 图片坐标
      var blockPositionX = this.blockPosition[i].x;
      var blockPositionY = this.blockPosition[i].y;
      // 是否最后
      var isLastBlock = i === this.blockImgPosition.length - 1;
      template += `
        <div
          class="block"
          style="
            width: ${this.blockWidth}px;
            height: ${this.blockHeight}px;
            background-image: url('${this.puzzleImg}');
            background-position: ${-blockImgX}px ${-blockImgY}px;
            left: ${blockPositionX}px; 
            top: ${blockPositionY}px;
            opacity: ${isLastBlock ? 0 : 1}
          "
          ref="${isLastBlock ? 'empty' : 'block'}"
        ></div>
      `;
    }
    this.oPuzzle.setAttribute('class', 'puzzle'); // 设置类名
    this.oPuzzle.style.width = this.puzzleWidth + 'px';
    this.oPuzzle.style.height = this.puzzleHeight + 'px'; // 游戏设置大小
    this.layer.setAttribute('class', 'layer'); // 设置蒙层
    this.layer.style.width = this.puzzleWidth + "px";
    this.layer.style.height = this.puzzleHeight + "px";
    // 开始按钮
    var startBtn = this.layer.querySelector(".startBtn");
    if (!startBtn) {
      this.startBtn = document.createElement('div');
      this.startBtn.setAttribute('class', 'startBtn');
      this.startBtn.innerText = "开始";
      this.layer.appendChild(this.startBtn);
    } else {
      this.startBtn = startBtn;
    }
    this.startBtn.style.display = "block";
    // 重新/下一关
    var restart = this.layer.querySelector(".restart");
    if (!restart) {
      this.restart = document.createElement('div');
      this.restart.setAttribute('class', 'restart');
      this.layer.appendChild(this.restart);
    } else {
      this.restart = restart;
    }
    this.restart.style.display = "none";
    // 提示成功
    var tips = this.layer.querySelector(".tips");
    if (!tips) {
      this.tips = document.createElement('div');
      this.tips.setAttribute('class', 'tips');
      this.layer.appendChild(this.tips);
    } else {
      this.tips = tips;
    }
    this.tips.style.display = "none";
    this.oPuzzle.innerHTML = template;
  },
  handle: function () {
    // 开始点击
    this.startBtn.onclick = () => {
      this.layer.style.display = "none";
      this.startBtn.style.display = "none";
      this.startTime = Date.now(); // 开始时间
    }
    // 下关/重新开始
    this.restart.onclick = () => {
      typeof this.resCallback == "function" && this.resCallback();
    }
    // 滑块点击事件
    this.oPuzzle.onclick = (e) => {
      var dom = e.target;
      var isBlock = dom.classList.contains('block') && dom.getAttribute('ref') === 'block'; // 移动块
      if (isBlock) {
        this.handleBlock(dom);
      }
    };
  },
  handleBlock: function (dom) {
    // 判断当前点击元素是否和空白元素相邻
    var canMove = this.checkMove(dom);
    // 如果不相邻，则什么都不做
    if (!canMove) {
      return
    };
    // 交换点击元素和空白元素的位置
    this.moveBlock(dom);
    // 交换位置后判断是否胜利
    this.checkWin();
  },
  // 方块空白检测
  checkMove: function (oBlock) {
    // 获取block元素当前的行和列
    var blockIndex = this.getEleIndex(oBlock);
    var blockRow = blockIndex.row;
    var blockCol = blockIndex.col;
    // 获取empty元素当前的行和列
    var emptyIndex = this.getEleIndex(this.oEmptyBlock);
    var emptyRow = emptyIndex.row;
    var emptyCol = emptyIndex.col;
    // 判断是否列相同，行相差为1
    // 判断是否行相同，列相差为1
    // 将结果返回出去
    return blockCol === emptyCol && Math.abs(blockRow - emptyRow) === 1 || blockRow === emptyRow && Math.abs(blockCol - emptyCol) === 1;
  },
  // 获取元素行列
  getEleIndex: function (dom) {
    var left = dom.offsetLeft;
    var top = dom.offsetTop;
    var row = Math.round(top / this.blockHeight);
    var col = Math.round(left / this.blockWidth);
    return {
      row: row,
      col: col
    };
  },
  // 移动点击方块
  moveBlock: function (oBlock) {
    // 获取block元素的left值和top值
    var blockLeft = oBlock.style.left;
    var blockTop = oBlock.style.top;
    // 设置block元素的left和top为empty元素的left和top
    oBlock.style.left = this.oEmptyBlock.style.left;
    oBlock.style.top = this.oEmptyBlock.style.top;
    // 设置empty元素的left和top为block元素的left和top
    this.oEmptyBlock.style.left = blockLeft;
    this.oEmptyBlock.style.top = blockTop;
  },
  checkWin: function () {
    // 在该函数中判断是否胜利
    var isWin = true; // 声明一个变量isWin，存放是否胜利，默认为true
    // 遍历所有的block元素（除了empty）
    for (var i = 0; i < this.oBlockList.length; i++) {
      var oBlock = this.oBlockList[i];
      var blockLeft = parseInt('-' + oBlock.style.left); // 拿到元素的left值，取反，因为背景图片的方向都为负值
      var blockTop = parseInt('-' + oBlock.style.top); // 拿到元素的top值，取反，因为背景图片的方向都为负值
      var imgLeft = parseInt(oBlock.style.backgroundPositionX); // 拿到元素背景图片位置方向x
      var imgTop = parseInt(oBlock.style.backgroundPositionY); // 拿到元素背景图片位置方向y
      if (!(blockLeft === imgLeft && blockTop === imgTop)) {
        isWin = false;
        break;
      }
    }
    if (isWin) {
      this.winGame();
    }
  },
  winGame: function () {
    var durationTime = (Date.now() - this.startTime);
    var minute = Math.floor(durationTime / (1000 * 60)); // 分
    var second = Math.floor((durationTime - 1000 * 60 * minute) / 1000); // 秒
    setTimeout(() => {
      this.layer.style.display = "flex";
      this.tips.innerText = `恭喜你，拼成功啦，用时 ${minute < 10 ? '0' + minute : minute}:${second < 10 ? "0" + second : second} 分`;
      this.tips.style.display = "block";
      typeof this.tipCallback == "function" && this.tipCallback(this.restart);
    }, 300);
    this.startTime = 0; // 重置时间
    this.oEmptyBlock.style.opacity = 1;
    this.oPuzzle.onclick = null;
  },
}
// 难度等级
var index = 0;
// 滑块构造函数
function Puzzle(options) {
  index++;
  this.init(options);
}
// 游戏封面
var imgArr = ["./img/belle1.jpg", "./img/belle2.jpg", "./img/belle3.jpg", "./img/belle4.jpg", "./img/belle4.jpg"];
// 递归进行难度设置
function recursive() {
  new Puzzle({
    el: '#app',
    data: {
      width: 500,
      height: 500,
      row: 3 + index,
      col: 3 + index,
      img: imgArr[index],
      tipCallback: function (dom1) {
        if (index >= imgArr.length) {
          dom1.innerHTML = "重新开始";
        } else {
          dom1.innerHTML = "下一关";
        }
        dom1.style.display = "block";
      },
      resCallback: function () {
        if (index >= imgArr.length) {
          location.reload();
        } else {
          recursive();
        }
      }
    },
  });
}
recursive();